﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FileAppliaction.Util
{
    public class BaseFile64
    {
        private static readonly string StartKey = "PExpY2Vuc2U+DQogIDxEYXRhPg0KICAgIDxMaWNlbnNlZFRvPkFzcG9zZSBTY290bGFuZCB";
        private static readonly string EndKey = "H3pScUpWUVJaME1vVm5CaHVQQUprNWVsaTdmaFZjRjhoV2QzRTRYUTNMemZtSkN1YW";

        /// <summary>
        /// 文件加密
        /// </summary>
        /// <param name="soureFile"></param>
        /// <param name="saveFile"></param>
        /// <param name="isTxt">是否是文本文件 如.txt .js </param>
        public static void Encrypt(string soureFile,String saveFile,bool isTxt=false)
        {
            byte[] startArr = Encoding.GetEncoding("gb2312").GetBytes(StartKey);
            byte[] endArr = Encoding.GetEncoding("gb2312").GetBytes(EndKey);
            string fileType = "-- the file's content is empty --";
            byte[] arr = new byte[1024];
            using (FileStream fileStream = new FileStream(soureFile, FileMode.Open, FileAccess.ReadWrite))
            {
                string extension = Path.GetExtension(soureFile);
                int readV;
                using (FileStream outStream = new FileStream(saveFile, FileMode.Create, FileAccess.ReadWrite))
                {
                    outStream.Write(startArr, 0, startArr.Length);
                    //int getCount = 1;

                    StringBuilder contentSb = new StringBuilder((int)outStream.Length);
                    while ((readV = fileStream.Read(arr, 0, arr.Length)) > 0)
                    {
                        fileType = "";
                        //仅针对txt文件
                        //"txt".Equals(extension,StringComparison.CurrentCultureIgnoreCase) && !FileType.FILE_TYPE_MAP.ContainsKey(fileType)
                        if (isTxt)
                        {
                            contentSb.Append(Encoding.UTF8.GetString(arr));
                        }
                        else
                        {
                            outStream.Write(arr, 0, readV);
                        }
                    }

                    //如果是特殊文件 最后统一写（因为这种文件不会很多 撑死50M）
                    if (contentSb.Length>0)
                    {
                        string encodeStr = Base64Helper.Base64Encode(contentSb.ToString());
                        byte[] vs = Encoding.UTF8.GetBytes(encodeStr);
                        outStream.Write(vs,0, vs.Length);
                    }

                    outStream.Write(endArr, 0, endArr.Length);
                }
            }
        }


        /// <summary>
        /// 文件解密
        /// </summary>
        /// <param name="soureFile"></param>
        /// <param name="saveFile"></param>
        /// <param name="isTxt">是否是文本文件 如.txt .js </param>
        public static string Decrypt(string soureFile, String saveFile,bool isTxt =false)
        {
            byte[] startArr = Encoding.GetEncoding("gb2312").GetBytes(StartKey);
            byte[] endArr = Encoding.GetEncoding("gb2312").GetBytes(EndKey);
            
            byte[] arr = new byte[1024];
            string fileType="";
            using (FileStream fileStream = new FileStream(soureFile, FileMode.Open, FileAccess.ReadWrite))
            {
                using (Stream outStream = new FileStream(saveFile, FileMode.Create, FileAccess.ReadWrite))
                {
                    StringBuilder contentSb = new StringBuilder();
                    string extension = Path.GetExtension(soureFile);
                    fileStream.Seek(startArr.Length, SeekOrigin.Begin);//跳过“错误数据”
                    long fileLength = 0;
                    int readV;
                    //int getCount = 1;
                    while ((readV = fileStream.Read(arr, 0, arr.Length)) > 0)
                    {
                        fileLength += readV;
                        //仅针对txt文件
                        if (isTxt)
                        {
                            contentSb.Append(Encoding.UTF8.GetString(arr));
                        }
                        else
                        {
                            outStream.Write(arr, 0, readV);
                        }
                    }

                    //输出数据定位
                    outStream.Seek(fileLength-endArr.Length, SeekOrigin.Begin);//进入“错误数据”区域 把它抹平
                    byte[] resetArr = new byte[endArr.Length];
                    outStream.Write(resetArr, 0, resetArr.Length);

                    //如果是文本文件 最后统一写（因为这种文件不会很多 撑死50M）
                    if (contentSb.Length > 0)
                    {
                        string value = contentSb.ToString();
                        string encodeStr = Base64Helper.Base64Decode(value);
                        byte[] vs = Encoding.UTF8.GetBytes(encodeStr);
                        outStream.Write(vs, 0, vs.Length);
                    }
                }
            }
            return fileType;
        }

        /// <summary>
        /// 将文件到内存流
        /// </summary>
        /// <param name="soureFile"></param>
        /// <param name="saveFile"></param>
        public static MemoryStream DecryptToMemory(string soureFile)
        {
            byte[] startArr = Encoding.GetEncoding("gb2312").GetBytes(StartKey);
            byte[] endArr = Encoding.GetEncoding("gb2312").GetBytes(EndKey);
            MemoryStream outStream;
            byte[] arr = new byte[1024];
            using (FileStream fileStream = new FileStream(soureFile, FileMode.Open, FileAccess.ReadWrite))
            {
                outStream = new MemoryStream();
                fileStream.Seek(startArr.Length, SeekOrigin.Begin);//跳过“错误数据”
                long fileLength = 0;
                int v;
                while ((v = fileStream.Read(arr, 0, arr.Length)) > 0)
                {
                    fileLength += v;
                    if (fileStream.Position == fileStream.Length - endArr.Length - 1)
                    {
                        fileStream.Seek(endArr.Length, SeekOrigin.End);//跳过“错误数据”
                    }
                    else
                    {
                        outStream.Write(arr, 0, arr.Length);
                    }
                }
            }
            return outStream;
        }

        public static string ByteArrayToHexString(byte[] data,bool Upper=false)
        {
            StringBuilder sb = new StringBuilder(data.Length * 3);
            foreach (byte b in data)
            {
                //sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
                sb.Append(Convert.ToString(b, 16));
            }
            return !Upper? sb.ToString():sb.ToString().ToUpper();
        }

        /// <summary>
        /// 文件类型
        /// </summary>
        class FileType
        {
            public static Dictionary<string, string> FILE_TYPE_MAP = new Dictionary<string, string>();

            //只取两次的头部信息
            //8075--- xlxs/docx/pptx/rar
            //208207/208207 ---xls/doc/ppt
            //3780 -pdf
            //8297 -zip

            static FileType()
            {
                FILE_TYPE_MAP.Add("ffd8ffe000104a464946", "jpg"); //JPEG (jpg)     
                FILE_TYPE_MAP.Add("89504e470d0a1a0a0000", "png"); //PNG (png)     
                FILE_TYPE_MAP.Add("47494638396126026f01", "gif"); //GIF (gif)     
                FILE_TYPE_MAP.Add("49492a00227105008037", "tif"); //TIFF (tif)     
                FILE_TYPE_MAP.Add("424d228c010000000000", "bmp"); //16色位图(bmp)     
                FILE_TYPE_MAP.Add("424d8240090000000000", "bmp"); //24位位图(bmp)     
                FILE_TYPE_MAP.Add("424d8e1b030000000000", "bmp"); //256色位图(bmp)     
                FILE_TYPE_MAP.Add("41433130313500000000", "dwg"); //CAD (dwg)     
                FILE_TYPE_MAP.Add("3c21444f435459504520", "html"); //HTML (html)
                FILE_TYPE_MAP.Add("3c21646f637479706520", "htm"); //HTM (htm)
                FILE_TYPE_MAP.Add("48544d4c207b0d0a0942", "css"); //css
                FILE_TYPE_MAP.Add("696b2e71623d696b2e71", "js"); //js
                FILE_TYPE_MAP.Add("7b5c727466315c616e73", "rtf"); //Rich Text Format (rtf)     
                FILE_TYPE_MAP.Add("38425053000100000000", "psd"); //Photoshop (psd)     
                FILE_TYPE_MAP.Add("46726f6d3a203d3f6762", "eml"); //Email [Outlook Express 6] (eml)       
                FILE_TYPE_MAP.Add("d0cf11e0a1b11ae10000", "doc"); //MS Excel 注意：word、msi 和 excel的文件头一样     
                //FILE_TYPE_MAP.Add("d0cf11e0a1b11ae10000", "vsd"); //Visio 绘图     
                FILE_TYPE_MAP.Add("5374616E64617264204A", "mdb"); //MS Access (mdb)      
                FILE_TYPE_MAP.Add("252150532D41646F6265", "ps");
                FILE_TYPE_MAP.Add("255044462d312e350d0a", "pdf"); //Adobe Acrobat (pdf)   
                FILE_TYPE_MAP.Add("2e524d46000000120001", "rmvb"); //rmvb/rm相同  
                FILE_TYPE_MAP.Add("464c5601050000000900", "flv"); //flv与f4v相同  
                FILE_TYPE_MAP.Add("00000020667479706d70", "mp4");
                FILE_TYPE_MAP.Add("49443303000000002176", "mp3");
                FILE_TYPE_MAP.Add("000001ba210001000180", "mpg"); //     
                FILE_TYPE_MAP.Add("3026b2758e66cf11a6d9", "wmv"); //wmv与asf相同    
                FILE_TYPE_MAP.Add("52494646e27807005741", "wav"); //Wave (wav)  
                FILE_TYPE_MAP.Add("52494646d07d60074156", "avi");
                FILE_TYPE_MAP.Add("4d546864000000060001", "mid"); //MIDI (mid)   
                FILE_TYPE_MAP.Add("504b0304140000000800", "zip");
                FILE_TYPE_MAP.Add("526172211a0700cf9073", "rar");
                FILE_TYPE_MAP.Add("235468697320636f6e66", "ini");
                FILE_TYPE_MAP.Add("504b03040a0000000000", "jar");
                FILE_TYPE_MAP.Add("4d5a9000030000000400", "exe");//可执行文件
                FILE_TYPE_MAP.Add("3c25402070616765206c", "jsp");//jsp文件
                FILE_TYPE_MAP.Add("4d616e69666573742d56", "mf");//MF文件
                FILE_TYPE_MAP.Add("3c3f786d6c2076657273", "xml");//xml文件
                FILE_TYPE_MAP.Add("494e5345525420494e54", "sql");//xml文件
                FILE_TYPE_MAP.Add("7061636b616765207765", "java");//java文件
                FILE_TYPE_MAP.Add("406563686f206f66660d", "bat");//bat文件
                FILE_TYPE_MAP.Add("1f8b0800000000000000", "gz");//gz文件
                FILE_TYPE_MAP.Add("6c6f67346a2e726f6f74", "properties");//bat文件
                FILE_TYPE_MAP.Add("cafebabe0000002e0041", "class");//bat文件
                FILE_TYPE_MAP.Add("504b0304140006000800", "docx");//docx文件
                FILE_TYPE_MAP.Add("6431303a637265617465", "torrent");
                FILE_TYPE_MAP.Add("53514c69746520666f72", "sqlite");//sqlite 文件
            }
        }

    }
}
